/**
 * Copyright © 2016-2025 The Thingsboard Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.terracloud.server.common.data.log;

import com.terracloud.server.common.data.id.DeviceId;
import com.terracloud.server.common.data.id.PlatformLogId;
import com.terracloud.server.common.data.id.TerminalLogId;
import com.terracloud.server.common.data.id.TenantId;
import com.terracloud.server.common.data.id.UserId;
import lombok.extern.slf4j.Slf4j;
import java.util.UUID;

/**
 * 统一日志工具类
 * 提供简单易用的日志记录方法，开发人员可以通过一行代码记录所有类型的日志
 */
@Slf4j
public class UnifiedLogUtil {
    
    private static volatile Object unifiedLogService;
    private static volatile Boolean serviceChecked = false;
    
    // 私有构造函数，防止实例化
    private UnifiedLogUtil() {
    }
    
    /**
     * 获取 UnifiedLogService 实例
     * 
     * @return UnifiedLogService 实例或 null（如果无法获取）
     */
    private static BaseUnifiedLogService getUnifiedLogService() {
        if (serviceChecked) {
            return (BaseUnifiedLogService) unifiedLogService;
        }
        
        synchronized (UnifiedLogUtil.class) {
            if (serviceChecked) {
                return (BaseUnifiedLogService) unifiedLogService;
            }
            
            try {
                // 尝试通过反射获取 Spring 上下文中的 UnifiedLogService
                Class<?> springContextHolderClass = Class.forName("com.terracloud.server.config.SpringContextHolder");
                Object applicationContext = springContextHolderClass.getMethod("getApplicationContext").invoke(null);
                if (applicationContext != null) {
                    unifiedLogService = applicationContext.getClass().getMethod("getBean", Class.class)
                            .invoke(applicationContext, Class.forName("com.terracloud.server.service.log.UnifiedLogService"));
                }
            } catch (Exception e) {
                log.debug("Failed to get UnifiedLogService from Spring context: {}", e.getMessage());
                unifiedLogService = null;
            } finally {
                serviceChecked = true;
            }
        }
        
        return (BaseUnifiedLogService) unifiedLogService;
    }
    
    /**
     * 获取当前安全用户信息
     * 
     * @return SecurityUser 当前安全用户，如果无法获取则返回null
     */
    private static Object getCurrentUser() {
        try {
            Class<?> securityContextHolderClass = Class.forName("org.springframework.security.core.context.SecurityContextHolder");
            Object context = securityContextHolderClass.getMethod("getContext").invoke(null);
            if (context != null) {
                Object authentication = context.getClass().getMethod("getAuthentication").invoke(context);
                if (authentication != null) {
                    Object principal = authentication.getClass().getMethod("getPrincipal").invoke(authentication);
                    if (principal != null) {
                        // 检查是否是 SecurityUser 类型
                        if (principal.getClass().getName().equals("com.terracloud.server.service.security.model.SecurityUser")) {
                            return principal;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.debug("Failed to get current user from security context: {}", e.getMessage());
        }
        return null;
    }
    
    /**
     * 获取当前租户ID
     * 
     * @return TenantId 当前租户ID，如果无法获取则返回系统租户ID
     */
    private static TenantId getCurrentTenantId() {
        try {
            Object user = getCurrentUser();
            if (user != null) {
                Object tenantId = user.getClass().getMethod("getTenantId").invoke(user);
                if (tenantId instanceof TenantId) {
                    return (TenantId) tenantId;
                }
            }
        } catch (Exception e) {
            log.debug("Failed to get current tenant ID: {}", e.getMessage());
        }
        return TenantId.SYS_TENANT_ID;
    }
    
    /**
     * 获取当前用户ID
     * 
     * @return UserId 当前用户ID，如果无法获取则返回null
     */
    private static UserId getCurrentUserId() {
        try {
            Object user = getCurrentUser();
            if (user != null) {
                Object id = user.getClass().getMethod("getId").invoke(user);
                if (id instanceof UserId) {
                    return (UserId) id;
                }
            }
        } catch (Exception e) {
            log.debug("Failed to get current user ID: {}", e.getMessage());
        }
        return null;
    }
    
    /**
     * 获取当前用户名
     * 
     * @return String 当前用户名，如果无法获取则返回"Unknown"
     */
    private static String getCurrentUserName() {
        try {
            Object user = getCurrentUser();
            if (user != null) {
                // 使用 getEmail() 方法获取用户名，因为系统中以邮箱作为用户名使用
                Object email = user.getClass().getMethod("getEmail").invoke(user);
                if (email != null) {
                    return email.toString();
                }
            }
        } catch (Exception e) {
            log.debug("Failed to get current user name: {}", e.getMessage());
        }
        return "Unknown";
    }
    
    /**
     * 获取当前请求的客户端IP地址
     * 
     * @return String 客户端IP地址，如果无法获取则返回"Unknown"
     */
    private static String getCurrentClientIpAddress() {
        try {
            Class<?> requestContextHolderClass = Class.forName("org.springframework.web.context.request.RequestContextHolder");
            Object attributes = requestContextHolderClass.getMethod("getRequestAttributes").invoke(null);
            if (attributes != null) {
                Object request = attributes.getClass().getMethod("getRequest").invoke(attributes);
                if (request != null) {
                    // 尝试获取 X-Forwarded-For 头
                    Object xForwardedFor = request.getClass().getMethod("getHeader", String.class).invoke(request, "X-Forwarded-For");
                    if (xForwardedFor != null && !xForwardedFor.toString().isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor.toString())) {
                        // X-Forwarded-For可能包含多个IP地址，取第一个
                        String xff = xForwardedFor.toString();
                        int index = xff.indexOf(',');
                        if (index != -1) {
                            return xff.substring(0, index);
                        } else {
                            return xff;
                        }
                    }
                    
                    // 尝试获取 X-Real-IP 头
                    Object xRealIp = request.getClass().getMethod("getHeader", String.class).invoke(request, "X-Real-IP");
                    if (xRealIp != null && !xRealIp.toString().isEmpty() && !"unknown".equalsIgnoreCase(xRealIp.toString())) {
                        return xRealIp.toString();
                    }
                    
                    // 获取远程地址
                    Object remoteAddr = request.getClass().getMethod("getRemoteAddr").invoke(request);
                    if (remoteAddr != null) {
                        return remoteAddr.toString();
                    }
                }
            }
        } catch (Exception e) {
            log.debug("Failed to get client IP address: {}", e.getMessage());
        }
        return "Unknown";
    }
    
    /**
     * 记录终端日志
     * 
     * @param deviceId 设备ID
     * @param deviceName 设备名称
     * @param logType 日志类型
     * @param logLevel 日志级别
     * @param contentSummary 内容摘要
     * @param contentDetails 内容详情（可选）
     * @param processor 处理人（可选）
     * @param processStatus 处理状态（可选）
     * @param slaStatus SLA状态（可选）
     * @param slaDeadline SLA截止时间（可选）
     * @param duration 持续时间（可选）
     * @param isCritical 是否关键日志（可选）
     */
    public static void logTerminal(DeviceId deviceId, String deviceName, LogType logType, LogLevel logLevel,
                                  String contentSummary, String contentDetails, 
                                  String processor, LogStatus processStatus, String slaStatus, 
                                  Long slaDeadline, Long duration, Boolean isCritical) {
        // 记录日志到SLF4J
        log.info("[TerminalLog] DeviceId: {}, DeviceName: {}, Type: {}, Level: {}, Content: {}", 
                deviceId, deviceName, logType, logLevel, contentSummary);
                
        // 尝试保存日志到数据库
        try {
            BaseUnifiedLogService service = getUnifiedLogService();
            if (service != null) {
                // 创建 TerminalLog 实例并填充字段
                TerminalLog terminalLog = new TerminalLog();
                terminalLog.setId(new TerminalLogId(UUID.randomUUID()));
                terminalLog.setCreatedTime(System.currentTimeMillis());
                terminalLog.setDeviceId(deviceId);
                terminalLog.setDeviceName(deviceName);
                terminalLog.setLogType(logType);
                terminalLog.setLogLevel(logLevel);
                terminalLog.setContentSummary(contentSummary);
                terminalLog.setContentDetails(contentDetails);
                terminalLog.setProcessor(processor);
                terminalLog.setProcessStatus(processStatus);
                terminalLog.setSlaStatus(slaStatus);
                terminalLog.setSlaDeadline(slaDeadline);
                terminalLog.setDuration(duration);
                terminalLog.setIsCritical(isCritical);
                terminalLog.setOccurTime(System.currentTimeMillis());
                
                // 自动填充租户ID、用户ID等信息
                terminalLog.setTenantId(getCurrentTenantId());
                
                // 调用服务保存日志
                service.logTerminal(terminalLog);
            }
        } catch (Exception e) {
            log.warn("Failed to save terminal log to database: {}", e.getMessage());
        }
    }
    
    /**
     * 记录平台日志
     * 
     * @param logType 日志类型
     * @param logLevel 日志级别
     * @param operationContent 操作内容
     * @param operationDetails 操作详情（可选）
     * @param businessId 业务ID（可选）
     * @param operationParams 操作参数（可选）
     * @param statusTransition 状态转换（可选）
     * @param exceptionInfo 异常信息（可选）
     * @param ipAddress IP地址（可选）
     * @param status 状态（可选）
     */
    public static void logPlatform(LogType logType, LogLevel logLevel, String operationContent, 
                                  String operationDetails, String businessId, String operationParams,
                                  String statusTransition, String exceptionInfo, String ipAddress, String status) {
        // 记录日志到SLF4J
        log.info("[PlatformLog] Type: {}, Level: {}, Content: {}, Details: {}, BusinessId: {}, Params: {}, StatusTransition: {}, Exception: {}, IP: {}, Status: {}", 
                logType, logLevel, operationContent, operationDetails, businessId, operationParams, 
                statusTransition, exceptionInfo, ipAddress, status);
                
        // 尝试保存日志到数据库
        try {
            BaseUnifiedLogService service = getUnifiedLogService();
            if (service != null) {
                // 创建 PlatformLog 实例并填充字段
                PlatformLog platformLog = new PlatformLog();
                platformLog.setId(new PlatformLogId(UUID.randomUUID()));
                platformLog.setCreatedTime(System.currentTimeMillis());
                platformLog.setLogType(logType);
                platformLog.setLogLevel(logLevel);
                platformLog.setOperationContent(operationContent);
                platformLog.setOperationDetails(operationDetails);
                platformLog.setBusinessId(businessId);
                platformLog.setOperationParams(operationParams);
                platformLog.setStatusTransition(statusTransition);
                platformLog.setExceptionInfo(exceptionInfo);
                platformLog.setIpAddress(ipAddress != null ? ipAddress : getCurrentClientIpAddress());
                platformLog.setStatus(status);
                platformLog.setOccurTime(System.currentTimeMillis());
                
                // 自动填充租户ID、用户ID、用户名等信息
                platformLog.setTenantId(getCurrentTenantId());
                platformLog.setUserId(getCurrentUserId());
                platformLog.setUserName(getCurrentUserName());
                
                // 调用服务保存日志
                service.logPlatform(platformLog);
            }
        } catch (Exception e) {
            log.warn("Failed to save platform log to database: {}", e.getMessage());
        }
    }
}